using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Services;
using AuthService.Options;
using MatrixFramework.Keycloak.Abstractions.Services;
using MatrixFramework.Keycloak.Abstractions.Models;
using MatrixFramework.Core.Results;
using Volo.Abp.Domain.Repositories;
using AuthService.Domain.Auth;
using AutoMapper;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using System.Text;

namespace AuthService.Services;

/// <summary>
/// 认证授权服务实现
/// </summary>
public class AuthService : ApplicationService, IAuthService
{
    private readonly ILogger<AuthService> _logger;
    private readonly IOptions<AuthServiceOptions> _options;
    private readonly IDistributedCache<AuthService> _cache;
    private readonly IKeycloakAdminService _keycloakAdminService;
    private readonly IRepository<AuthSession, Guid> _authSessionRepository;
    private readonly IAuthSessionRepository _customAuthSessionRepository;
    private readonly IMapper _objectMapper;

    public AuthService(
        ILogger<AuthService> logger,
        IOptions<AuthServiceOptions> options,
        IDistributedCache<AuthService> cache,
        IKeycloakAdminService keycloakAdminService,
        IRepository<AuthSession, Guid> authSessionRepository,
        IAuthSessionRepository customAuthSessionRepository,
        IMapper objectMapper)
    {
        _logger = logger;
        _options = options;
        _cache = cache;
        _keycloakAdminService = keycloakAdminService;
        _authSessionRepository = authSessionRepository;
        _customAuthSessionRepository = customAuthSessionRepository;
        _objectMapper = objectMapper;
    }

    /// <summary>
    /// 用户登录
    /// </summary>
    public virtual async Task<LoginResultDto> LoginAsync(LoginRequestDto input)
    {
        _logger.LogInformation("用户登录尝试: {Username} - Realm: {Realm}", input.Username, input.Realm);

        try
        {
            // 1. 验证用户凭据
            var validationResult = await _keycloakAdminService.ValidateUserCredentialsAsync(
                input.Username,
                input.Password,
                input.Realm);

            if (!validationResult.IsSuccess || !validationResult.Data)
            {
                _logger.LogWarning("用户登录失败: {Username} - 凭据验证失败", input.Username);
                throw new UserFriendlyException("用户名或密码错误", "AUTH_001");
            }

            // 2. 获取用户信息
            var userResult = await _keycloakAdminService.GetUserByUsernameAsync(input.Username, input.Realm);
            if (!userResult.IsSuccess || userResult.Data == null)
            {
                _logger.LogWarning("用户登录失败: {Username} - 无法获取用户信息", input.Username);
                throw new UserFriendlyException("用户信息获取失败", "AUTH_002");
            }

            var userInfo = userResult.Data;

            // 3. 获取用户角色和权限
            var rolesResult = await _keycloakAdminService.GetUserRolesAsync(userInfo.Id, input.Realm);
            var permissionsResult = await _keycloakAdminService.GetUserPermissionsAsync(userInfo.Id, input.Realm);

            var roles = rolesResult.IsSuccess ? rolesResult.Data ?? new List<string>() : new List<string>();
            var permissions = permissionsResult.IsSuccess ? permissionsResult.Data ?? new List<string>() : new List<string>();

            // 4. 生成JWT Token
            var accessToken = await GenerateJwtTokenAsync(userInfo, roles, permissions, input.Realm);
            var refreshToken = await GenerateRefreshTokenAsync(userInfo.Id, input.Realm);

            // 5. 创建认证会话
            var authSession = new AuthSession(
                GuidGenerator.Create(),
                new Guid(userInfo.Id),
                Guid.NewGuid().ToString(),
                Guid.NewGuid().ToString()
            );

            authSession.SetTenantId(CurrentTenant.Id);
            authSession.IpAddress = GetClientIpAddress();
            authSession.UserAgent = GetClientUserAgent();
            authSession.ExpiresAt = DateTime.Now.AddMinutes(_options.Value.AccessTokenLifetimeMinutes);
            authSession.RefreshTokenId = Guid.Parse(refreshToken);

            await _authSessionRepository.InsertAsync(authSession);

            // 6. 构建用户上下文
            var userContext = new UserContextDto
            {
                UserId = userInfo.Id,
                Username = userInfo.Username,
                Email = userInfo.Email ?? string.Empty,
                FirstName = userInfo.FirstName ?? string.Empty,
                LastName = userInfo.LastName ?? string.Empty,
                Name = $"{userInfo.FirstName} {userInfo.LastName}".Trim(),
                Roles = roles,
                Permissions = permissions,
                Realm = input.Realm,
                TenantId = CurrentTenant.Id,
                LoginTime = DateTime.Now,
                LastActivityTime = DateTime.Now
            };

            _logger.LogInformation("用户登录成功: {Username} - UserId: {UserId}", input.Username, userInfo.Id);

            return new LoginResultDto
            {
                AccessToken = accessToken,
                RefreshToken = refreshToken,
                TokenType = "Bearer",
                ExpiresIn = _options.Value.AccessTokenLifetimeMinutes * 60,
                RefreshExpiresIn = _options.Value.RefreshTokenLifetimeMinutes * 60,
                UserContext = userContext
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "用户登录过程中发生错误: {Username}", input.Username);
            throw new UserFriendlyException("登录失败，请稍后重试", "AUTH_003");
        }
    }

    /// <summary>
    /// 用户登出
    /// </summary>
    public virtual async Task LogoutAsync(LogoutRequestDto input)
    {
        _logger.LogInformation("用户登出");

        // 简化实现，实际应该清理缓存和会话
        await Task.CompletedTask;
    }

    /// <summary>
    /// 刷新Token
    /// </summary>
    public virtual async Task<RefreshTokenResultDto> RefreshTokenAsync(RefreshTokenRequestDto input)
    {
        _logger.LogInformation("刷新Token请求");

        try
        {
            // 1. 验证刷新令牌的有效性
            var principal = ValidateJwtToken(input.RefreshToken);
            if (principal == null)
            {
                _logger.LogWarning("刷新Token失败: 无效的刷新令牌");
                throw new UserFriendlyException("无效的刷新令牌", "AUTH_008");
            }

            var userId = principal.FindFirst(JwtRegisteredClaimNames.Sub)?.Value;
            var realm = principal.FindFirst("realm")?.Value;

            if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(realm))
            {
                throw new UserFriendlyException("令牌信息不完整", "AUTH_009");
            }

            // 2. 验证缓存中的刷新令牌
            var isValidRefreshToken = await ValidateRefreshTokenAsync(input.RefreshToken, userId, realm);
            if (!isValidRefreshToken)
            {
                _logger.LogWarning("刷新Token失败: 刷新令牌已过期或无效 - UserId: {UserId}", userId);
                throw new UserFriendlyException("刷新令牌已过期", "AUTH_010");
            }

            // 3. 获取用户信息
            var userResult = await _keycloakAdminService.GetUserAsync(userId, realm);
            if (!userResult.IsSuccess || userResult.Data == null)
            {
                throw new UserFriendlyException("用户不存在", "AUTH_011");
            }

            var userInfo = userResult.Data;

            // 4. 获取用户角色和权限
            var rolesResult = await _keycloakAdminService.GetUserRolesAsync(userInfo.Id, realm);
            var permissionsResult = await _keycloakAdminService.GetUserPermissionsAsync(userInfo.Id, realm);

            var roles = rolesResult.IsSuccess ? rolesResult.Data ?? new List<string>() : new List<string>();
            var permissions = permissionsResult.IsSuccess ? permissionsResult.Data ?? new List<string>() : new List<string>();

            // 5. 生成新的访问令牌和刷新令牌
            var newAccessToken = await GenerateJwtTokenAsync(userInfo, roles, permissions, realm);
            var newRefreshToken = await GenerateRefreshTokenAsync(userInfo.Id, realm);

            // 6. 更新认证会话
            var authSession = await _authSessionRepository.FirstOrDefaultAsync(x => x.UserId == new Guid(userId) && x.IsActive);
            if (authSession != null)
            {
                authSession.UpdateLastActivity();
                authSession.ExpiresAt = DateTime.Now.AddMinutes(_options.Value.AccessTokenLifetimeMinutes);
                await _authSessionRepository.UpdateAsync(authSession);
            }

            // 7. 清除旧的刷新令牌缓存
            var oldCacheKey = $"refresh_token:{userId}:{realm}";
            await _cache.RemoveAsync(oldCacheKey);

            _logger.LogInformation("Token刷新成功: UserId: {UserId}", userId);

            return new RefreshTokenResultDto
            {
                AccessToken = newAccessToken,
                RefreshToken = newRefreshToken,
                TokenType = "Bearer",
                ExpiresIn = _options.Value.AccessTokenLifetimeMinutes * 60,
                RefreshExpiresIn = _options.Value.RefreshTokenLifetimeMinutes * 60
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "刷新Token过程中发生错误");
            throw new UserFriendlyException("Token刷新失败", "AUTH_012");
        }
    }

    /// <summary>
    /// 验证Token
    /// </summary>
    public virtual async Task<TokenValidationResultDto> ValidateTokenAsync(string token)
    {
        _logger.LogInformation("验证Token");

        try
        {
            var principal = ValidateJwtToken(token);
            if (principal == null)
            {
                return new TokenValidationResultDto
                {
                    IsValid = false,
                    ErrorMessage = "无效的令牌"
                };
            }

            var userId = principal.FindFirst(JwtRegisteredClaimNames.Sub)?.Value;
            var username = principal.FindFirst(JwtRegisteredClaimNames.UniqueName)?.Value;
            var email = principal.FindFirst(JwtRegisteredClaimNames.Email)?.Value;
            var realm = principal.FindFirst("realm")?.Value;
            var exp = principal.FindFirst(JwtRegisteredClaimNames.Exp)?.Value;

            // 验证令牌是否在数据库会话中仍然有效
            if (!string.IsNullOrEmpty(userId))
            {
                var authSession = await _authSessionRepository.FirstOrDefaultAsync(
                    x => x.UserId == new Guid(userId) && x.IsActive);

                if (authSession == null || authSession.IsExpired())
                {
                    return new TokenValidationResultDto
                    {
                        IsValid = false,
                        ErrorMessage = "会话已过期或不存在"
                    };
                }
            }

            var tokenInfo = new TokenInfoDto
            {
                Active = true,
                Subject = userId ?? string.Empty,
                Username = username ?? string.Empty,
                Email = email ?? string.Empty,
                Name = $"{principal.FindFirst(JwtRegisteredClaimNames.GivenName)?.Value} {principal.FindFirst(JwtRegisteredClaimNames.FamilyName)?.Value}".Trim(),
                Roles = principal.FindAll(ClaimTypes.Role).Select(c => c.Value).ToList(),
                Realm = realm ?? "master",
                IssuedAt = principal.FindFirst(JwtRegisteredClaimNames.Iat)?.Value ?? string.Empty,
                Issuer = principal.FindFirst(JwtRegisteredClaimNames.Iss)?.Value ?? string.Empty
            };

            // 解析过期时间
            if (long.TryParse(exp, out var expSeconds))
            {
                tokenInfo.ExpirationTime = DateTimeOffset.FromUnixTimeSeconds(expSeconds).DateTime;
            }

            return new TokenValidationResultDto
            {
                IsValid = true,
                TokenInfo = tokenInfo
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Token验证过程中发生错误");
            return new TokenValidationResultDto
            {
                IsValid = false,
                ErrorMessage = "令牌验证失败"
            };
        }
    }

    /// <summary>
    /// 获取Token信息
    /// </summary>
    public virtual async Task<TokenInfoDto> GetTokenInfoAsync(string token)
    {
        _logger.LogInformation("获取Token信息");

        return await Task.FromResult(new TokenInfoDto
        {
            Active = true,
            Subject = "sample-user-id",
            Username = "sample-user",
            Email = "user@example.com",
            ExpirationTime = DateTime.Now.AddHours(1)
        });
    }

    /// <summary>
    /// 获取用户上下文
    /// </summary>
    public virtual async Task<UserContextDto> GetUserContextAsync(string token)
    {
        _logger.LogInformation("获取用户上下文");

        return await Task.FromResult(new UserContextDto
        {
            UserId = "sample-user-id",
            Username = "sample-user",
            Email = "user@example.com",
            Roles = new List<string> { "user" },
            Permissions = new List<string> { "read" },
            LoginTime = DateTime.Now,
            LastActivityTime = DateTime.Now
        });
    }

    /// <summary>
    /// 检查用户权限
    /// </summary>
    public virtual async Task<bool> HasPermissionAsync(string userId, string permission)
    {
        _logger.LogInformation("检查用户权限: {UserId} - {Permission}", userId, permission);
        return await Task.FromResult(true);
    }

    /// <summary>
    /// 获取用户权限列表
    /// </summary>
    public virtual async Task<List<string>> GetUserPermissionsAsync(string userId)
    {
        _logger.LogInformation("获取用户权限列表: {UserId}", userId);
        return await Task.FromResult(new List<string> { "read", "write" });
    }

    /// <summary>
    /// 获取用户角色列表
    /// </summary>
    public virtual async Task<List<string>> GetUserRolesAsync(string userId)
    {
        _logger.LogInformation("获取用户角色列表: {UserId}", userId);
        return await Task.FromResult(new List<string> { "user", "admin" });
    }

    /// <summary>
    /// 密码重置
    /// </summary>
    public virtual async Task ResetPasswordAsync(ResetPasswordRequestDto input)
    {
        _logger.LogInformation("密码重置: {Email}", input.Email);
        await Task.CompletedTask;
    }

    /// <summary>
    /// 修改密码
    /// </summary>
    public virtual async Task ChangePasswordAsync(ChangePasswordRequestDto input)
    {
        _logger.LogInformation("修改密码: {UserId}", input.UserId);

        try
        {
            // 验证当前密码
            var userResult = await _keycloakAdminService.GetUserAsync(input.UserId, input.Realm);
            if (!userResult.IsSuccess || userResult.Data == null)
            {
                throw new UserFriendlyException("用户不存在", "AUTH_004");
            }

            // 验证新密码
            if (input.NewPassword != input.ConfirmPassword)
            {
                throw new UserFriendlyException("新密码与确认密码不匹配", "AUTH_005");
            }

            if (input.NewPassword.Length < 8)
            {
                throw new UserFriendlyException("密码长度至少8位", "AUTH_006");
            }

            // 重置密码
            var resetResult = await _keycloakAdminService.ResetPasswordAsync(
                input.UserId,
                input.NewPassword,
                input.Realm);

            if (!resetResult.IsSuccess)
            {
                throw new UserFriendlyException("密码修改失败", "AUTH_007");
            }

            // 注销用户所有会话
            await _keycloakAdminService.LogoutUserAsync(input.UserId, input.Realm);

            _logger.LogInformation("密码修改成功: {UserId}", input.UserId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "修改密码过程中发生错误: {UserId}", input.UserId);
            throw;
        }
    }

    #region 辅助方法

    /// <summary>
    /// 生成JWT访问令牌
    /// </summary>
    private async Task<string> GenerateJwtTokenAsync(UserInfo userInfo, List<string> roles, List<string> permissions, string realm)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_options.Value.JwtSecretKey);

        var claims = new List<Claim>
        {
            new Claim(JwtRegisteredClaimNames.Sub, userInfo.Id),
            new Claim(JwtRegisteredClaimNames.UniqueName, userInfo.Username),
            new Claim(JwtRegisteredClaimNames.Email, userInfo.Email ?? string.Empty),
            new Claim(JwtRegisteredClaimNames.GivenName, userInfo.FirstName ?? string.Empty),
            new Claim(JwtRegisteredClaimNames.FamilyName, userInfo.LastName ?? string.Empty),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim("realm", realm),
            new Claim("tenant_id", CurrentTenant.Id?.ToString() ?? string.Empty)
        };

        // 添加角色声明
        foreach (var role in roles)
        {
            claims.Add(new Claim("role", role));
            claims.Add(new Claim(ClaimTypes.Role, role));
        }

        // 添加权限声明
        foreach (var permission in permissions)
        {
            claims.Add(new Claim("permission", permission));
        }

        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Expires = DateTime.UtcNow.AddMinutes(_options.Value.AccessTokenLifetimeMinutes),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
            Issuer = _options.Value.JwtIssuer,
            Audience = _options.Value.JwtAudience
        };

        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }

    /// <summary>
    /// 生成刷新令牌
    /// </summary>
    private async Task<string> GenerateRefreshTokenAsync(string userId, string realm)
    {
        var refreshToken = Guid.NewGuid().ToString();

        // 将刷新令牌存储到缓存中，有效期30天
        var cacheKey = $"refresh_token:{userId}:{realm}";
        await _cache.SetAsync(cacheKey, refreshToken, TimeSpan.FromDays(30));

        return refreshToken;
    }

    /// <summary>
    /// 验证刷新令牌
    /// </summary>
    private async Task<bool> ValidateRefreshTokenAsync(string refreshToken, string userId, string realm)
    {
        var cacheKey = $"refresh_token:{userId}:{realm}";
        var storedToken = await _cache.GetAsync<string>(cacheKey);

        return storedToken == refreshToken;
    }

    /// <summary>
    /// 验证JWT令牌
    /// </summary>
    private ClaimsPrincipal ValidateJwtToken(string token)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_options.Value.JwtSecretKey);

            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = true,
                ValidIssuer = _options.Value.JwtIssuer,
                ValidateAudience = true,
                ValidAudience = _options.Value.JwtAudience,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };

            var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
            return principal;
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 获取客户端IP地址
    /// </summary>
    private string GetClientIpAddress()
    {
        var context = HttpContextAccessor?.HttpContext;
        if (context == null) return string.Empty;

        var ipAddress = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
        if (!string.IsNullOrEmpty(ipAddress))
        {
            return ipAddress.Split(',')[0].Trim();
        }

        return context.Connection.RemoteIpAddress?.ToString() ?? string.Empty;
    }

    /// <summary>
    /// 获取客户端User-Agent
    /// </summary>
    private string GetClientUserAgent()
    {
        var context = HttpContextAccessor?.HttpContext;
        return context?.Request.Headers["User-Agent"].ToString() ?? string.Empty;
    }

    #endregion
}